/*
 * ecDisplay.c
 *
 *  Created on: 2009. 11. 18.
 *      Author: jingul.kim
 */

#include "ecDisplay.h"

#define NATIVESIG(t, v) dispatchNative(t, LOWORD(v), HIWORD(v))
#define MOUSESIG(t, b, v) dispatchMouse(t, b, LOWORD(v), HIWORD(v))

JavaVM *vm;

LRESULT CALLBACK msgProc(HWND, UINT, WPARAM, LPARAM);

JNIEXPORT jboolean JNICALL Java_ec_sys_Display_create(JNIEnv *env, jobject obj) {
	env->GetJavaVM(&vm);

	EC_WND *wnd = new EC_WND();

	wnd->hInstance = GetModuleHandle(NULL);

	WNDCLASS &wc = wnd->wc;
	wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
	wc.lpfnWndProc = (WNDPROC) msgProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = wnd->hInstance;
	wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);

	wc.hbrBackground = NULL;
	wc.lpszMenuName = NULL;
	wc.lpszClassName = CLASS_NAME;

	if (RegisterClass(&wc) == 0) {
		puts("regist failed");
		return JNI_FALSE;
	}

	wnd->hWnd = CreateWindow(CLASS_NAME, _T("Endless Code Test"), WS_OVERLAPPEDWINDOW
			| WS_CLIPCHILDREN | WS_CLIPSIBLINGS, CW_USEDEFAULT, CW_USEDEFAULT,
			CW_USEDEFAULT, 0, NULL, (HMENU) NULL, GetModuleHandle(NULL), NULL);

	if (wnd->hWnd == NULL) {
		puts("create failed");
		return JNI_FALSE;
	}

	jclass cls = env->GetObjectClass(obj);
	jfieldID fid = env->GetFieldID(cls, "handle", "I");

	env->SetIntField(obj, fid, (jint) wnd);

	return JNI_TRUE;
}
JNIEXPORT void JNICALL Java_ec_sys_Display_destroy(JNIEnv *env, jobject obj) {
	EC_WND *wnd = getHandle(env, obj);

	DestroyWindow(wnd->hWnd);
	delete wnd;
}

JNIEXPORT void JNICALL Java_ec_sys_Display_show(JNIEnv *env, jobject obj) {
	EC_WND *wnd = getHandle(env, obj);

	ShowWindow(wnd->hWnd, SW_SHOW);
}

JNIEXPORT void JNICALL Java_ec_sys_Display_hide(JNIEnv *env, jobject obj) {
	EC_WND *wnd = getHandle(env, obj);

	ShowWindow(wnd->hWnd, SW_HIDE);
}

JNIEXPORT void JNICALL Java_ec_sys_Display_setSize(JNIEnv *env, jobject obj,
		jint w, jint h) {
	EC_WND *wnd = getHandle(env, obj);

	SetWindowPos(wnd->hWnd, HWND_TOP, 0, 0, w, h, SWP_NOMOVE);
}

JNIEXPORT void JNICALL Java_ec_sys_Display_dispatch(JNIEnv *env, jobject obj) {
	static MSG msg;

	jclass cls = env->GetObjectClass(obj);
	jmethodID id = env->GetMethodID(cls, "nextFrame", "()V");

	while (true) {
		if (!env->ExceptionOccurred() && PeekMessage(&msg, NULL, 0, 0,
				PM_REMOVE)) {
			if (msg.message == WM_QUIT) {
				return;
			}

			TranslateMessage(&msg);
			DispatchMessage(&msg);
		} else {
			if (!env->ExceptionOccurred()) {
				env->CallVoidMethod(obj, id);
			}
		}
	}
}

EC_WND* getHandle(JNIEnv *env, jobject obj) {
	jclass cls = env->GetObjectClass(obj);
	jfieldID fid = env->GetFieldID(cls, "handle", "I");

	return (EC_WND*) env->GetIntField(obj, fid);
}

LRESULT CALLBACK msgProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) {
	switch (iMessage) {
	case WM_CREATE:
		return 0;
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_SIZE:
		NATIVESIG(RESIZE, lParam);
		break;
	case WM_LBUTTONUP:
		MOUSESIG(UP, LEFT, lParam);
		break;
	case WM_LBUTTONDOWN:
		MOUSESIG(DOWN, LEFT, lParam);
		break;
	case WM_MBUTTONUP:
		MOUSESIG(UP, MEDIUM, lParam);
		break;
	case WM_MBUTTONDOWN:
		MOUSESIG(DOWN, MEDIUM, lParam);
		break;
	case WM_RBUTTONUP:
		MOUSESIG(UP, RIGHT, lParam);
		break;
	case WM_RBUTTONDOWN:
		MOUSESIG(DOWN, RIGHT, lParam);
		break;
	case WM_MOUSEMOVE:
		MOUSESIG(MOVE, wParam, lParam);
		break;
	case WM_KEYUP:
		break;
	case WM_KEYDOWN:
		break;
	}

	return DefWindowProc(hWnd, iMessage, wParam, lParam);
}

void dispatchNative(jint type, jint lflag, jint rflag) {
	JNIEnv *env;

	vm->GetEnv((void**) &env, JNI_VERSION_1_6);

	if (!env->ExceptionOccurred()) {
		jclass cls = env->FindClass("ec/sys/Display");
		jmethodID id = env->GetStaticMethodID(cls, "dispatchNative", "(III)V");

		env->CallStaticVoidMethod(cls, id, type, lflag, rflag);
	}
}

void dispatchMouse(jint type, jint button, jint x, jint y) {
	JNIEnv *env;

	vm->GetEnv((void**) &env, JNI_VERSION_1_6);

	if (!env->ExceptionOccurred()) {
		jclass cls = env->FindClass("ec/sys/Display");
		jmethodID id = env->GetStaticMethodID(cls, "dispatchMouse", "(IIII)V");

		env->CallStaticVoidMethod(cls, id, type, button, x, y);
	}
}
